<?php
/**
 * Plugin registry.
 *
 * A repository for plugins, each registered with a key.
 *
 * @copyright     Copyright 2008-2010, LilCake.net
 * @link          http://lilcake.net LilCake.net
 * @package       lil
 * @subpackage    lil
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
App::uses('LilObjectRegistry', 'Lil.Lib');
/**
 * LilPluginRegistry
 *
 * @package       lil
 * @subpackage    lil.libs
 */
class LilPluginRegistry {
	private static $instance;
	
     // A private constructor; prevents direct creation of object
    private function __construct()  {
        $this->__initPlugins();
    }
    // Prevent users to clone the instance
    public function __clone() {
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }

/**
 * Return a singleton instance of the LilPluginRegistry.
 *
 * @return LilPluginRegistry instance
 * @access public
 */
	public static function &getInstance() {
		if (!isset(self::$instance)) {
			$c = __CLASS__;
			self::$instance = new $c;
		}
		return self::$instance;
	}
	
	private function __initPlugins() {
		App::uses('Dispatcher', 'Routing');
		$r = new Dispatcher(); 
		$req = $r->parseParams(new CakeRequest);
		
		$resp = new CakeResponse(array('charset' => Configure::read('App.encoding')));
		
		// do other plugins
		$plugins = Configure::read('Lil.plugins');
		foreach ((array)$plugins as $plugin) {
			$this->__initPlugin('Lil' . $plugin, $req, $resp);
		}
		
		// try to init app plugin after other plugins so app plugin can modify others
		$this->__initPlugin(null, $req, $resp);
	}
	
/**
 * __initPlugin method
 *
 * @return void
 */
	private function __initPlugin($plugin_name = null, $req = null, $resp = null) {
		if (!empty($plugin_name)) {
			$import_path = $plugin_name . '.Controller';
			$controller_name = $plugin_name . 'PluginController';
		} else {
			// this is app controller plugin
			$import_path = 'Controller';
			$controller_name = 'AppPluginController';
			$plugin_name = null;
		}
		
		App::uses($controller_name, $import_path);
		if (class_exists($controller_name) && ($plugin = new $controller_name(null, $resp))) {
			
			
			$plugin->setRequest($req);
			$plugin->constructClasses();
			$plugin->beforeFilter();
			
			// have to set this manually so finding view paths work (Email component)
			if (!empty($plugin_name)) {
				$plugin->plugin = Inflector::underscore($plugin_name);
				$real_plugin_name = $plugin_name;
			} else {
				$real_plugin_name = 'App';
			}
			
			$key = Inflector::underscore($real_plugin_name);
			if (!isset($this->__objects[$key])) {
				$this->__objects[$key] =& $plugin;
			}
		}
	}
/**
 * callPluginHandlers method
 *
 * @param string $handler
 * @return void
 */
	public function callPluginHandlers($caller, $handler, $args = null) {
		$_this =& LilPluginRegistry::getInstance();
		
		$ret = $args;
		$plugins = array();
		if (isset($_this->__objects)) $plugins = array_keys($_this->__objects);
		foreach ((array)$plugins as $plugin_key) {
			$plugin = $_this->__objects[$plugin_key];
			if (
				!empty($plugin->handlers[$handler]) &&
				method_exists($plugin, $plugin->handlers[$handler]['function'])
			)
			{
				$ret = call_user_func_array(
					array($plugin, $plugin->handlers[$handler]['function']),
					array(
						'controller'  => $caller,
						'args'   => (array)$ret,
						'params' => (array)$plugin->handlers[$handler]['params'],
					)
				);
			}
		}
		return $ret;
	}
}